import { cloneDeep, debounce, throttle } from 'lodash'

class Util {
/**
 * 构造树型结构数据
 * @param {*} data 数据源
 * @param {*} id id字段 默认 'id'
 * @param {*} parentId 父节点字段 默认 'parentId'
 * @param {*} children 孩子节点字段 默认 'children'
 */
 static handleTree(data, id, parentId, children) {
  let config = {
    id: id || 'id',
    parentId: parentId || 'parentId',
    childrenList: children || 'children'
  };

  var childrenListMap = {};
  var nodeIds = {};
  var tree = [];

  for (let d of data) {
    let parentId = d[config.parentId];
    if (childrenListMap[parentId] == null) {
      childrenListMap[parentId] = [];
    }
    nodeIds[d[config.id]] = d;
    childrenListMap[parentId].push(d);
  }

  for (let d of data) {
    let parentId = d[config.parentId];
    if (nodeIds[parentId] == null) {
      tree.push(d);
    }
  }

  for (let t of tree) {
    adaptToChildrenList(t);
  }

  function adaptToChildrenList(o) {
    if (childrenListMap[o[config.id]] !== null) {
      o[config.childrenList] = childrenListMap[o[config.id]];
    }
    if (o[config.childrenList]) {
      for (let c of o[config.childrenList]) {
        adaptToChildrenList(c);
      }
    }
  }
  return tree;
}
  // 深度遍历配置树
  static deepTravel (obj,fuc) {
    if (Array.isArray(obj)){//1、如果是数组 每一项item都执行一遍自身函数
      obj.forEach(item =>{
        this.deepTravel(item,fuc)
      })
      return
    }
    if (obj && obj.children){
      fuc(obj)//2、item执行函数以 list[item.name] = item 的形式添加到list中
      this.deepTravel(obj.children, fuc) //2.1、 如果有子路由再次执行加入到list缓存中
      return
    }
    if (obj.name){//3、最后一层路由 加到缓存
      fuc(obj)
    }
  }
  // 深度遍历配置树, 摘取叶子节 递归函数
  static deepTravelRouter (config,fuc) {
    if (Array.isArray(config)){//1、判断config是否是数组 每一项subConfig都执行一遍自身函数
      config.forEach(subConfig =>{
        this.deepTravelRouter(subConfig,fuc)
      })
    }else if (config.children && config.children.length){//2、执行到subConfig，判断是否有子路由参数且不为空
      config.children.forEach(subConfig =>{
        this.deepTravelRouter(subConfig,fuc)
      })
    } else {//以上条件筛选完父路由只剩下了子路由subConfig，执行参数中都fuc函数处理路由并push到homeRouter中，即使不要这个参数单独抽离出来一个函数也可
      fuc(config)
    }
  }

  //转换时间戳的方法
  static changeTimeStyle(){

  }

  //使用第三方lodash  深拷贝
  static _cloneDeep(data){
    return cloneDeep(data)
  }
  /**
   * 防抖函数
   * 所谓防抖，就是指触发事件后在 n 秒内函数只能执行一次，如果在 n 秒内又触发了事件，则会重新计算函数执行时间。
   * 持续触发不执行不触发的一段时间之后再执行
   *
   * @param {*} func 函数体
   * @param {*} wait 延时
   */
  static _debounce (func, wait) {
    return debounce(func,wait)
  }
  /**
   * 节流函数
   * 所谓节流，就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。
   * 持续触发并不会执行多次到一定时间再去执行
   * @param {*} func 函数体
   * @param {*} wait 延时
   */
  static _throttle (func, wait,ThrottleSettings) {
    return throttle(func,wait,ThrottleSettings)
  }


  /**
   * 返回 n 位的随机字符串
   * @param {Number} n
   */
  static getRandomStr(n = 6){
    let str = ''
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'
    for (let i = 0; i < n; i += 1) {
      str += chars.charAt(Math.floor(Math.random() * 62))
    }
    return str
  }

  //判断权限
  /**
   permissions= ["创建Banner item","删除Banner item","更新Banner item"]。   // 接口返回的用户权限：
   route.permission=['超级管理员独有权限']   // config舞台页面权限：
   some()：用于检测数组中的元素是否满足指定条件
   如果有一个元素满足条件，则表达式返回true , 剩余的元素不会再执行检测
   如果没有满足条件的元素，则返回false
   * */
  static hasPermission(permissions,route,user){
    if (user && user.admin){//用户是管理员获取所有权限
      return true
    }
    if (route.permission){ //需要权限的页面 且用户含有此权限
      return permissions.some(permission => route.permission.indexOf(permission) > -1)
    }
    return true //不需要的页面
  }
  static getBirthByIdCard(idCard){
    let birthday = "";
    if(idCard != null && idCard != ""){
      if(idCard.length == 15){
        birthday = "19"+idCard.slice(6,12);
      } else if(idCard.length == 18){
        birthday = idCard.slice(6,14);
      }
      birthday = birthday.replace(/(.{4})(.{2})/,"$1-$2-");
      //通过正则表达式来指定输出格式为:1990-01-01
    }
    return birthday;

  }
  static getSexByIdCard(idCard){
    let sexStr = '';
    if (parseInt(idCard.slice(-2, -1)) % 2 == 1) {
      sexStr = 'man';
    }
    else {
      sexStr = 'woman';
    }
    return sexStr;
  }

  // 返回一个布尔值，表示某个数组是否包含给定的值，与字符串的includes方法类似。该方法属于ES7，但Babel转码器已经支持。
  // 下面代码用来检查当前环境是否支持该方法，如果不支持，部署一个简易的替代版本。
  static hasArrayIncludes(arr,value){
    return Array.prototype.includes ? arr.includes(value) : arr.some(el => el === value)
  }
}

export default Util
